package com.xb.loan.usercenter.account.impl;

import com.xb.loan.account.service.ICashService;
import com.xb.loan.account.service.bean.CashBillVO;
import com.xb.loan.account.service.bean.CashInfoVO;
import com.xb.loan.account.service.constant.AccountConst;
import com.xb.loan.account.service.exception.IAccountServiceException;
import com.xb.loan.log.exception.BizException;
import com.xb.loan.usercenter.account.common.VerifySet;
import com.xb.loan.usercenter.account.dao.bean.CashBill;
import com.xb.loan.usercenter.account.dao.bean.CashInfo;
import com.xb.loan.usercenter.service.user.IUserService;
import com.xb.loan.usercenter.service.user.bean.UserInfoVO;
import com.xb.loan.util.SpringHelper;
import com.xb.loan.util.cache.redis.comm.FormatOperation;
import com.xb.loan.util.common.ObjectOperation;
import com.xb.loan.util.log.DefaultLoggerFacotry;
import com.xb.loan.util.log.LogFormatUtil;
import com.xb.loan.util.mybatis.MyTransactional;
import com.xb.loan.util.refself.BeanSelfAware;
import com.xb.loan.util.strategy.TableNoAllocatorFactory;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 北京掌中彩信息科技有限公司源代码，版权归北京掌中彩信息科技有限公司所有。
 * 
 * 项目名称 : common-biz
 * 创建日期 : 2015年9月13日
 * 修改历史 : 
 *     1. [2015年9月13日]创建文件 by wenju.song
 */
@Service("cashService")
public class CashServiceImpl extends AbstractCashService implements ICashService, BeanSelfAware {
    
    @Autowired
	IUserService userService;
	private static Logger logger = DefaultLoggerFacotry.getLogger(CashServiceImpl.class);
	private CashServiceImpl proxySelf; // ② 表示代理对象，不是目标对象

	public void setSelf(Object proxyBean) { // 通过InjectBeanSelfProcessor注入自己（目标对象）的AOP代理对象
		this.proxySelf = (CashServiceImpl) proxyBean;
	}
	
	@Override
	public void createCashInfo(CashInfoVO cashInfoVO) throws BizException {
		VerifySet.verifyCashInfoVO(cashInfoVO);
		CashInfo cashInfo = ObjectOperation.convertByClasses(cashInfoVO, CashInfo.class);
		cashInfoDao.insert(cashInfo);
	}
	
	@Override
	public CashInfoVO queryCashInfoByUserId(String userId) throws BizException {
		VerifySet.verifyUserId(userId);
		
		CashInfoVO result = null;
		UserInfoVO userInfoVo=userService.queryUserInfoById(userId);
		if(userInfoVo !=null)
		    return queryCashInfoById(userInfoVo.getAccountId());
		return result;
	}

	@Override
	public CashInfoVO queryCashInfoById(String accountId) throws BizException {
		VerifySet.verifyAccountId(accountId);

		CashInfoVO result = null;
		CashInfo cashInfo = cashInfoDao.queryCashInfoById(accountId);

		if (cashInfo == null)
			return result;
		result = (CashInfoVO) ObjectOperation.convertByClasses(cashInfo, CashInfoVO.class);
		return result;
	}

    @Override
    public CashBillVO queryCashBillByForeignId(String userId, String foreignId, int billType) throws BizException {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("foreignId", foreignId);
        params.put("billType", billType);
        params.put("tableId", TableNoAllocatorFactory.getAllocator("t_cash_bill").getTableNo(userId));
        return ObjectOperation.convertByClasses(cashBillDao.queryCashBillByForeignId(params), CashBillVO.class);
    }

	@Override
	public List<CashBillVO> queryCashBill(String userId, Integer feeType, String billType, String startDate, String endDate, int pageNum, int numPerPage) throws BizException {
		VerifySet.verifyUserId(userId);

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userId", userId);
		params.put("feeType", feeType);
		params.put("billType", billType);
		params.put("startDate", startDate);
		params.put("endDate", endDate);
		params.put("tableId", TableNoAllocatorFactory.getAllocator("t_cash_bill").getTableNo(userId));
		params.put("pageNum", pageNum);
		params.put("numPerPage", numPerPage);

		List<CashBill> cashBillList = cashBillDao.queryCashBill(params);
		return ObjectOperation.convertByClassesList(cashBillList, CashBillVO.class);
	}

	@Override
	public int queryCashBillCount(String userId, Integer feeType, String billType, String startDate, String endDate) throws BizException {
		VerifySet.verifyUserId(userId);

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userId", userId);
		params.put("feeType", feeType);
		params.put("billType", billType);
		params.put("startDate", startDate);
		params.put("endDate", endDate);
		params.put("tableId", TableNoAllocatorFactory.getAllocator("t_cash_bill").getTableNo(userId));
		return cashBillDao.queryCashBillCount(params);
	}

	@Override
	public List<CashBillVO> queryHisCashBill(String userId, Integer feeType, Integer billType, String startDate, String endDate, int pageNum, int numPerPage) throws BizException {
		VerifySet.verifyUserId(userId);

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userId", userId);
		params.put("feeType", feeType);
		params.put("billType", billType);
		params.put("startDate", startDate);
		params.put("endDate", endDate);
		params.put("tableId", TableNoAllocatorFactory.getAllocator("t_cash_bill").getTableNo(userId));
		params.put("pageNum", pageNum);
        params.put("numPerPage", numPerPage);

		List<CashBill> cashBillList = cashBillDao.queryHisCashBill(params);

		return ObjectOperation.convertByClassesList(cashBillList, CashBillVO.class);
	}

	@Override
	public int queryHisCashBillCount(String userId, Integer feeType, Integer billType, String startDate, String endDate) throws BizException {
		VerifySet.verifyUserId(userId);

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userId", userId);
		params.put("feeType", feeType);
		params.put("billType", billType);
		params.put("startDate", startDate);
		params.put("endDate", endDate);
		params.put("tableId", TableNoAllocatorFactory.getAllocator("t_cash_bill").getTableNo(userId));
		return cashBillDao.queryHisCashBillCount(params);
	}
	
	@Override
	public int updateCashInfo(String accountId, String partnerId, Integer feeType, Double creditMoney, Double tCreditMoney, String tCreditEndTimeStamp, Integer status) throws BizException {
		VerifySet.verifyAccountId(accountId);

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("accountId", accountId);
		params.put("partnerId", partnerId);
		params.put("feeType", feeType);
		params.put("creditMoney", creditMoney);
		params.put("tCreditMoney", tCreditMoney);
		params.put("tCreditEndTimeStamp", tCreditEndTimeStamp);
		params.put("status", status);
		
		return cashInfoDao.updateByPrimaryKeySelective(params);
	}

	@Override
	public int clearExpiredTmpCredit() throws BizException {
		String currentTime = FormatOperation.formatDateToYMDH(new Date());
		return cashInfoDao.clearExpiredTmpCredit(currentTime);
	}

	@Override
	public void addMoney(String foreignId, UserInfoVO userInfoVO, double money, int billType, String accountPeriod) throws BizException {
		// 验证用户和账户信息
		CashInfo cashInfo = cashInfoDao.queryCashInfoById(userInfoVO.getAccountId());
		VerifySet.verifyCashInfoIsNormal(cashInfo);

		CashInfo cashInfoDelta = new CashInfo();
		cashInfoDelta.setAccountId(userInfoVO.getAccountId());
		cashInfoDelta.setMoney(money);

		CashBill cashBill = createCashBill(userInfoVO, billType, foreignId, accountPeriod);
		cashBill.setBillIncome(money);

		//CashServiceImpl self = SpringHelper.getBean("cashService");
		proxySelf.addMoneyTransaction(userInfoVO, cashInfoDelta, cashBill);
		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "cash_add", foreignId, userInfoVO.getUserId(), money, billType}));
	}

	@Override
	public void deductMoney(String foreignId, UserInfoVO userInfoVO, double money, int billType, String accountPeriod) throws BizException {
		// 验证金额和账户信息
		VerifySet.verifyMoney(money, foreignId);
		VerifySet.verifyUserInfoVO(userInfoVO);
		CashInfo cashInfo = cashInfoDao.queryCashInfoById(userInfoVO.getAccountId());
		VerifySet.verifyCashInfoIsNormal(cashInfo);

		CashInfo cashInfoDelta = new CashInfo();
		cashInfoDelta.setAccountId(userInfoVO.getAccountId());
		cashInfoDelta.setMoney(money);

		CashBill cashBill = createCashBill(userInfoVO, billType, foreignId, accountPeriod);
		cashBill.setBillExpend(money);

		CashServiceImpl self = SpringHelper.getBean("cashService");
		self.deductMoneyTransaction(userInfoVO, cashInfoDelta, cashBill);
		
		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "cash_deduct", foreignId, userInfoVO.getUserId(), money, billType}));
	}

	@Override
	public void deductCredit(String foreignId, UserInfoVO userInfoVO, double money, int billType, String accountPeriod) throws BizException {
		// 验证金额和账户信息
		VerifySet.verifyMoney(money, foreignId);
		CashInfo cashInfo = cashInfoDao.queryCashInfoById(userInfoVO.getAccountId());
		VerifySet.verifyCashInfoIsNormal(cashInfo);

		CashInfo cashInfoDelta = new CashInfo();
		cashInfoDelta.setAccountId(userInfoVO.getAccountId());
		cashInfoDelta.setMoney(money);

		CashBill cashBill = createCashBill(userInfoVO, billType, foreignId, accountPeriod);
		cashBill.setBillExpend(money);

		CashServiceImpl self = SpringHelper.getBean("cashService");
		self.deductCreditTransaction(userInfoVO, cashInfoDelta, cashBill);

		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "cash_deduct", foreignId, userInfoVO.getUserId(), money, billType}));
	}
	
	@Override
	public void deductTmpCredit(String foreignId, UserInfoVO userInfoVO, double money, int billType, String accountPeriod) throws BizException {
		// 验证金额和账户信息
		VerifySet.verifyMoney(money, foreignId);
		CashInfo cashInfo = cashInfoDao.queryCashInfoById(userInfoVO.getAccountId());
		VerifySet.verifyCashInfoIsNormal(cashInfo);

		CashInfo cashInfoDelta = new CashInfo();
		cashInfoDelta.setAccountId(userInfoVO.getAccountId());
		cashInfoDelta.setMoney(money);

		CashBill cashBill = createCashBill(userInfoVO, billType, foreignId, accountPeriod);
		cashBill.setBillExpend(money);

		CashServiceImpl self = SpringHelper.getBean("cashService");
		self.deductTmpCreditTransaction(userInfoVO, cashInfoDelta, cashBill);

		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "cash_deduct", foreignId, userInfoVO.getUserId(), money, billType}));
	}

	@Override
	public void transfer(String foreignId, UserInfoVO fromUserInfoVO, UserInfoVO toUserInfoVO, double money, int outBill, int inBill, String accountPeriod) throws BizException {
		// 验证金额和账户信息
		VerifySet.verifyMoney(money, foreignId);
		CashInfo fromCashInfo = cashInfoDao.queryCashInfoById(fromUserInfoVO.getAccountId());
		VerifySet.verifyCashInfoIsNormal(fromCashInfo);
		CashInfo toCashInfo = cashInfoDao.queryCashInfoById(toUserInfoVO.getAccountId());
		VerifySet.verifyCashInfoIsNormal(toCashInfo);

		CashInfo fromCashInfoDelta = new CashInfo();
		fromCashInfoDelta.setAccountId(fromUserInfoVO.getAccountId());
		fromCashInfoDelta.setMoney(money);

		CashBill fromCashBill = createCashBill(fromUserInfoVO, outBill, foreignId, accountPeriod);
		fromCashBill.setBillExpend(money);

		CashInfo toCashInfoDelta = new CashInfo();
		toCashInfoDelta.setAccountId(toUserInfoVO.getAccountId());
		toCashInfoDelta.setMoney(money);

		CashBill toCashBill = createCashBill(toUserInfoVO, inBill, foreignId, accountPeriod);
		toCashBill.setBillIncome(money);
		CashServiceImpl self = SpringHelper.getBean("cashService");
		self.transferTransaction(fromUserInfoVO, fromCashInfoDelta, fromCashBill, toUserInfoVO, toCashInfoDelta, toCashBill);
		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "cash_deduct", foreignId, fromUserInfoVO.getUserId(), money, outBill}));
		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "cash_add", foreignId, toUserInfoVO.getUserId(), money, inBill}));
	}

	@Override
	public void purchaseTransfer(String foreignId, UserInfoVO fromUserInfoVO, UserInfoVO toUserInfoVO, double money, int outBill, int inBill, String accountPeriod) throws BizException {
		// 验证金额和账户信息
		VerifySet.verifyMoney(money, foreignId);
		CashInfo fromCashInfo = cashInfoDao.queryCashInfoById(fromUserInfoVO.getAccountId());
		VerifySet.verifyCashInfoIsNormal(fromCashInfo);
		CashInfo toCashInfo = cashInfoDao.queryCashInfoById(toUserInfoVO.getAccountId());
		VerifySet.verifyCashInfoIsNormal(toCashInfo);

		CashInfo fromCashInfoDelta = new CashInfo();
		fromCashInfoDelta.setAccountId(fromUserInfoVO.getAccountId());
		fromCashInfoDelta.setMoney(money);

		CashBill fromCashBill = createCashBill(fromUserInfoVO, outBill, foreignId, accountPeriod);
		fromCashBill.setBillExpend(money);

		CashInfo toCashInfoDelta = new CashInfo();
		toCashInfoDelta.setAccountId(toUserInfoVO.getAccountId());
		toCashInfoDelta.setMoney(money);

		CashBill toCashBill = createCashBill(toUserInfoVO, inBill, foreignId, accountPeriod);
		toCashBill.setBillIncome(money);

		CashServiceImpl self = SpringHelper.getBean("cashService");
		self.purchaseTransferTransaction(fromUserInfoVO, fromCashInfoDelta, fromCashBill, toUserInfoVO, toCashInfoDelta, toCashBill);
		
		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "cash_deduct", foreignId, fromUserInfoVO.getUserId(), money, outBill}));
		logger.info(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "userId", "money", "billType"},
				new Object[] { "cash_add", foreignId, toUserInfoVO.getUserId(), money, inBill}));
	}


	@Override
	public List<CashBillVO> queryCashBillAccess(String userId, String billType,
                                                String startDate, String endDate, String accessSQL, int pageNum,
                                                int numPerPage) throws BizException {
		
		VerifySet.verifyUserId(userId);
		
		Map<String,Object> map = new HashMap<String,Object>();
		
		map.put("tableId", TableNoAllocatorFactory.getAllocator("t_cash_bill").getTableNo(userId));
		map.put("userId", userId);
		map.put("billType", billType);
		map.put("startTime", startDate);
		map.put("endTime", endDate);
		map.put("accessSQL", accessSQL);
		map.put("pageNum", pageNum);
		map.put("numPerPage", numPerPage);
		
		List<CashBill> list = cashBillDao.queryCashBillAccess(map);
		
		return ObjectOperation.convertByClassesList(list, CashBillVO.class);
	}

	@Override
	public int queryCashBillAccessCount(String userId, String billType,
                                        String startDate, String endDate, String accessSQL)
			throws BizException {
		VerifySet.verifyUserId(userId);
		
		Map<String,Object> map = new HashMap<String,Object>();
		
		map.put("tableId", TableNoAllocatorFactory.getAllocator("t_cash_bill").getTableNo(userId));
		map.put("userId", userId);
		map.put("billType", billType);
		map.put("startTime", startDate);
		map.put("endTime", endDate);
		map.put("accessSQL", accessSQL);
		return cashBillDao.queryCashBillAccessCount(map);
	}
	@Override
	public List<Map<String, Object>> queryCashBillAccessMap(String userId,
                                                            String billType, String startDate, String endDate,
                                                            String accessSQL, int pageNum, int numPerPage) throws BizException {
		
		VerifySet.verifyUserId(userId);
		
		Map<String,Object> map = new HashMap<String,Object>();
		
		map.put("tableId", TableNoAllocatorFactory.getAllocator("t_cash_bill").getTableNo(userId));
		map.put("userId", userId);
		map.put("billType", billType);
		map.put("startTime", startDate);
		map.put("endTime", endDate);
		map.put("accessSQL", accessSQL);
		map.put("pageNum", pageNum);
		map.put("numPerPage", numPerPage);
		
		List<Map<String, Object>> list = cashBillDao.queryCashBillAccessMap(map);
		
		return list;
	}

	@Override
	public void flushes(String userId, String foreignId, int billType) throws BizException {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userId", userId);
		params.put("foreignId", foreignId);
		params.put("billType", billType);
		params.put("isFlushes", AccountConst.Flushes_No);
		List<CashBill> bills = cashBillDao.queryCashBill(params);
		if(bills == null || bills.size() <= 0)
			return;
		
		CashBill target = bills.get(0);
		
		Map<String, Object> billParams = new HashMap<String, Object>();
		billParams.put("tableId", target.getTableId());
		billParams.put("billId", target.getBillId());
		billParams.put("isFlushes", AccountConst.Flushes_Yes);
		
		Map<String, Object> cashStatParams = new HashMap<String, Object>();
		cashStatParams.put("accountId", target.getAccountId());
		
		CashInfo cashInfoDelta = new CashInfo();
		cashInfoDelta.setAccountId(target.getAccountId());
		
		double money = target.getBillExpend() > 0 ? target.getBillExpend() : target.getBillIncome();
		
		switch (billType) {
		case AccountConst.BillType_Purchase_Lottery:
			cashInfoDelta.setMoney(money);
			cashStatParams.put("throw", -money);
			break;
		case AccountConst.BillType_Proxy_Pay_Out:
			cashInfoDelta.setMoney(money);
			cashStatParams.put("transferEncash", -money);
			break;
		case AccountConst.BillType_Proxy_Pay_In:
			cashInfoDelta.setMoney(-money);
			cashStatParams.put("transferCharge", -money);
			break;
		case AccountConst.BillType_Credit_Pay_Out:
			cashInfoDelta.setMoney(money);
			cashStatParams.put("transferEncash", -money);
			break;
		case AccountConst.BillType_Credit_Pay_In:
			cashInfoDelta.setMoney(-money);
			cashStatParams.put("transferCharge", -money);
			break;
		case AccountConst.BillType_Encash:
			cashInfoDelta.setMoney(money);
			cashStatParams.put("bankEncash", -money);
			break;
		default:
			logger.error(LogFormatUtil.getFormatMsg(new String[]{"module", "foreignId", "billType", "msg"},
					new Object[]{"account", foreignId, billType, IAccountServiceException.invalidFlushesType.getMessage()}));
			throw IAccountServiceException.invalidFlushesType;
		}
		CashServiceImpl self = SpringHelper.getBean("cashService");
		self.flushesTransaction(cashInfoDelta, billParams, cashStatParams);
	}

	@MyTransactional
	public void flushesTransaction(CashInfo cashInfoDelta,
                                   Map<String, Object> billParams, Map<String, Object> cashStatParams) {
		cashInfoDao.addMoney(cashInfoDelta);
		cashBillDao.flushes(billParams);
		cashStatDao.updateCashStat(cashStatParams);
	}

	@Override
	public List<CashInfoVO> queryCashInfoByIds(String[] accountIds) {
				
		List<CashInfo> list = cashInfoDao.queryCashInfoByIds(accountIds);
		
		return ObjectOperation.convertByClassesList(list, CashInfoVO.class);
	}

	@Override
	public List<CashBillVO> queryCashBills(int tableId, String startDate, String endDate, int pageNum, int numPerPage)
			throws BizException {
		Map<String,Object> map = new HashMap<String,Object>();
		
		map.put("tableId", tableId);
		map.put("startDate", startDate);
		map.put("endDate", endDate);
		map.put("pageNum", pageNum);
		map.put("numPerPage", numPerPage);
		List<CashBill> list = cashBillDao.queryCashBills(map);
		
		return ObjectOperation.convertByClassesList(list, CashBillVO.class);
	}
	
}
